Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Api: ✨ Implementing Chatroom Join API: A Bounded Context Approach #184

Merged
merged 40 commits into from
Oct 29, 2024

Conversation

psychology50
Copy link
Member

@psychology50 psychology50 commented Oct 29, 2024

작업 이유

  • Authenticated User can join chatroom

작업 사항

1️⃣ Domain Business Rule

  • Domain Aspect
    • Password Requirements (Controller Layer): Password must be a six-digit integer. Null values are allowed for public rooms.
    • User Authentication (Security Layer): User must be authenticated.
    • Chatroom Capacity (Application Layer): Chatroom can accommodate up to 300 users
    • Password Match (Application Layer): Chatroom's password must match for entry.
    • User Validation (Domain Layer): User shouldn't be currently a member or have a ban history in the chatroom.
    • Immutability Check (Domain Layer): Fields like name and role in chat members are immutable.
    • New Join Handling (Application Layer): At the end of the service, handle the new join message within the chatroom.
    • When a user joins the chatroom, a new join message is implicitly handled within the chatroom.
  • Infrastructure Aspect
    • Concurrent Join Handling: If 350 users try to join simultaneously, only the first 299 will succeed (requires Distributed Lock).
    • If the chatroom resource is committed, a message must be sent to the queue at least once. (requires transaction rollback & message broker)

2️⃣ Refined Chatroom Join API with Bounded-Context Design

If you want more details, read my blog

image

  • We can implement this feature in two way
    1. Implement all feature in the socket application
    2. Separate HTTP requests from socket requests.
  • Choosing the first approach may violate principles of separation of concerns and bounded-context:
    • WebSocket’s role should focus on real-time message routing.
    • The creation of chat-member resources, however, is better managed through REST API.
  • Consequently, Chat-member context should be handled via HTTP API, while message context should remain within the socket.

3️⃣ Unit Test

  • Verify Business Rules:
    • Confirm chatroom capacity limits are enforced (e.g., chatroom is full).
    • Validate the provided password is correct.
    • Ensure events are published as expected.
  • Exceptional Cases:
    • Handle cases where the chatroom does not exist.
    • Address scenarios with missing user data.
    • Manage cases with incorrect passwords.

4️⃣ Integration Test

  • Distributed Lock Verification
    • Simultaneous room join scenario.
    • Confirm correct lock acquisition and release.
  • Transaction Verification
    • Test rollback functionality.
    • Ensure data consistency.
  • Flow Verification
    • Test happy path scenarios.
    • Verify real data is saved and received as expected.

리뷰어가 중점적으로 확인해야 하는 부분

image
image

  • I mapped out a design as though we have a socket-relay module, but it’s purely conceptual at this point.
    • This is because our server lacks sufficient memory for a full implementation. 😂
    • Therefore, I’ll proceed by implementing this feature within the socket application itself.
  • The remaining, unrelated tasks will be deferred to the next stage for completion (ex. socket-relay module)

발견한 이슈

  • When testing ApplicationEventPublisher and EventHandler using mocks in an integration test, @RecordingEvents and verify() cannot be used directly.
    • This is because ApplicationEventPublisher is part of the Spring context itself, meaning @MockBean won’t work in this instance.
    • Therefore, ApplicationEventPublisher cannot act as a mock instance.
    • Additionally, when you mock event handlers, ApplicationEvents will not accurately capture event counts.
    • Instead, an alternative approach should be used for event capture.
        ArgumentCaptor<ChatRoomJoinEvent> eventCaptor = ArgumentCaptor.forClass(ChatRoomJoinEvent.class);
      
        // when
        ResponseEntity<?> response = postJoining(user, chatRoom.getId(), new ChatMemberReq.Join(null));
      
        // then
        assertAll(
                () -> assertEquals(HttpStatus.OK, response.getStatusCode()),
                () -> assertTrue(chatMemberRepository.existsByChatRoomIdAndUserId(chatRoom.getId(), user.getId())),
                () -> verify(chatRoomJoinEventHandler).handle(eventCaptor.capture()),
                () -> {
                    ChatRoomJoinEvent capturedEvent = eventCaptor.getValue();
                    assertEquals(chatRoom.getId(), capturedEvent.chatRoomId());
                    assertEquals(user.getName(), capturedEvent.userName());
                }
        );

@psychology50 psychology50 added the enhancement New feature or request label Oct 29, 2024
@psychology50 psychology50 self-assigned this Oct 29, 2024
@psychology50 psychology50 merged commit afb5d86 into dev Oct 29, 2024
1 check passed
@psychology50 psychology50 deleted the feat/PW-592-join-chatroom branch October 29, 2024 11:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant